Skip to main content

Work with Database (Repositories)

Beauty Framework provides a clean and lightweight way to interact with databases through low-level SQL and Repository classes. There is no ORM yet — instead, we use a powerful interface: Beauty\Database\Connection\ConnectionInterface.

⚠️ The ORM is currently under development — this approach gives you full control in the meantime.

🧱 Example: UserRepository

You can create repository interfaces and their implementations in App\Repositories\Contracts and App\Repositories, respectively.

🔌 Interface

namespace App\Repositories\Contracts;

use App\DTO\Auth\RegisterDTO;
use App\Entities\User;

interface UserRepositoryInterface
{
public function findByEmail(string $email): User|null;
public function create(RegisterDTO $dto): User;
}

🧰 Implementation

namespace App\Repositories;

use App\DTO\Auth\RegisterDTO;
use App\Entities\User;
use App\Repositories\Contracts\UserRepositoryInterface;
use Beauty\Database\Connection\ConnectionInterface;
use PDO;

class UserRepository implements UserRepositoryInterface
{
public function __construct(
private ConnectionInterface $connection,
) {}

public function findByEmail(string $email): ?User
{
$stmt = $this->connection->query(
'SELECT id, name, email, password, created_at FROM users WHERE email = ? LIMIT 1',
[$email]
);

$data = $stmt->fetch(PDO::FETCH_ASSOC);

return $data ? $this->hydrateUser($data) : null;
}

public function create(RegisterDTO $dto): User
{
$stmt = $this->connection->query(
'INSERT INTO users (name, email, password) VALUES (?, ?, ?) RETURNING id, name, email, password, created_at',
[$dto->name, $dto->email, $dto->password]
);

return $this->hydrateUser($stmt->fetch(PDO::FETCH_ASSOC));
}

private function hydrateUser(array $data): User
{
return new User(
id: (int)$data['id'],
name: $data['name'],
email: $data['email'],
password: $data['password'],
createdAt: new \DateTimeImmutable($data['created_at']),
);
}
}

🧩 Entity Example

Entities are simple readonly value objects:

namespace App\Entities;

final readonly class User
{
public function __construct(
private int $id,
private string $name,
private string $email,
private string $password,
private \DateTimeImmutable $createdAt,
) {}

public function getId(): int { return $this->id; }
public function getName(): string { return $this->name; }
public function getEmail(): string { return $this->email; }
public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; }
public function getPassword(): string { return $this->password; }
}

🧾 Dependency Binding

To inject repository interfaces, register them in your App\Container\DI class in method configure:

use App\Repositories\Contracts\UserRepositoryInterface;
use App\Repositories\UserRepository;

$container->bind(UserRepositoryInterface::class, UserRepository::class);

All services and controllers will receive the implementation automatically via DI.

⚙️ Raw SQL Power

Beauty provides direct database access using ConnectionInterface:

public function update(string $sql, array $bindings = []): int;
public function select(string $sql, array $bindings = []): array;
public function transaction(callable $callback): mixed;

You have full control over performance, queries, and batching.

💡 Notes

  • Repositories encapsulate your data access logic
  • You can return rich entity objects or DTOs
  • All queries are safe and parameterized
  • ORM is in development — stay tuned

Use repositories to decouple persistence from business logic and keep your services clean.